package org.ghost.springboot.demo.util.http;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.auth.Credentials;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;
import org.ghost.springboot.demo.util.ExceptionUtil;
import org.ghost.springboot.demo.util.JacksonUtil;
import org.ghost.springboot.demo.util.UriUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class HttpRequestBuilder {
    private static final transient Logger logger = LoggerFactory.getLogger(HttpRequestBuilder.class);
    private transient HttpRequestBase httpRequestBase;
    private transient Credentials credentials;

    public HttpRequestBase getHttpRequestBase() {
        return httpRequestBase;
    }

    public HttpRequestBuilder() {
    }

    public HttpRequestBuilder(final HttpMethod method, final String url) {
        this.build(method, url);
    }

    public HttpRequestBuilder build(final HttpMethod method, final String url) {
        switch (method) {
            case GET:
                httpRequestBase = new HttpGet(url);
                break;
            case POST:
                httpRequestBase = new HttpPost(url);
                break;
            case PUT:
                httpRequestBase = new HttpPut(url);
                break;
            case DELETE:
                httpRequestBase = new HttpDelete(url);
                break;
            case PATCH:
                httpRequestBase = new HttpPatch(url);
                break;
            case OPTIONS:
                httpRequestBase = new HttpOptions(url);
                break;
            case HEAD:
                httpRequestBase = new HttpHead(url);
                break;
            case TRACE:
                httpRequestBase = new HttpTrace(url);
                break;
            default:
                ExceptionUtil.throwBusinessErrorException("HttpRequestBuilder.build", "方法未实现", logger);
                break;
        }

        return this;
    }

    /**
     * 添加请求头
     *
     * @param name
     * @param value
     * @return
     */
    public HttpRequestBuilder addHeader(String name, String value) {
        if (StringUtils.isNotEmpty(name) && StringUtils.isNotBlank(value)) {
            httpRequestBase.addHeader(name, value);
        }
        return this;
    }

    /**
     * 添加请求头
     *
     * @param headers
     * @return
     */
    public HttpRequestBuilder addHeaders(Map<String, String> headers) {
        if (MapUtils.isNotEmpty(headers)) {
            headers.forEach((key, value) -> httpRequestBase.addHeader(key, value));
        }
        return this;
    }

    /**
     * 拼接url参数
     *
     * @param name
     * @param value
     * @return
     */
    public HttpRequestBuilder addUrlPara(String name, String value) {
        if (StringUtils.isNotBlank(name)) {
            if (httpRequestBase.getURI().toString().contains("?")) {
                this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "&" + name + "=" + value));
            } else {
                this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "?" + name + "=" + value));
            }
        }
        return this;
    }

    /**
     * 拼接url参数
     *
     * @param params
     * @return
     */
    public HttpRequestBuilder addUrlPara(Map<String, String> params) {
        if (MapUtils.isNotEmpty(params)) {
            StringBuilder builder = new StringBuilder();
            params.forEach((key, value) -> {
                if (StringUtils.isNotBlank(key)) {
                    try {
                        if (builder.length() > 0) {
                            builder.append("&");
                        }
                        builder.append(URLEncoder.encode(key, "UTF-8")).append("=").append(URLEncoder.encode(value, "UTF-8"));
                    } catch (UnsupportedEncodingException e) {
                        logger.error("*****HttpRequestBuilder.addUrlPara:{}", e);
                    }
                }
            });

            if (builder.length() > 0) {
                if (httpRequestBase.getURI().toString().contains("?")) {
                    this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "&" + builder.toString()));
                } else {
                    this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "?" + builder.toString()));
                }
            }
        }

        return this;
    }

    /**
     * 拼接url参数
     *
     * @param param
     * @return
     */
    public HttpRequestBuilder addUrlPara(Object param) {
        if (param != null) {
            String value = UriUtil.urlParaEncode(param);
            if (StringUtils.isNotBlank(value)) {
                if (httpRequestBase.getURI().toString().contains("?")) {
                    this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "&" + value));
                } else {
                    this.httpRequestBase.setURI(URI.create(httpRequestBase.getURI().toString() + "?" + value));
                }
            }
        }
        return this;
    }

    /**
     * Form表单键值对参数
     *
     * @param params
     * @return
     * @throws UnsupportedEncodingException
     */
    public HttpRequestBuilder addFormPara(Map<String, String> params) throws UnsupportedEncodingException {
        if (this.httpRequestBase instanceof HttpEntityEnclosingRequestBase && MapUtils.isNotEmpty(params)) {
            List<NameValuePair> nameValuePairs = params.entrySet().stream()
                    .filter(it -> StringUtils.isNotBlank(it.getKey()))
                    .map(it -> new BasicNameValuePair(it.getKey(), it.getValue()))
                    .collect(Collectors.toList());

            ((HttpEntityEnclosingRequestBase) httpRequestBase).setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
        }

        return this;
    }

    /**
     * Body存放json数据
     *
     * @param body
     * @return
     */
    public HttpRequestBuilder addBody(Object body) {
        if (body != null && this.httpRequestBase instanceof HttpEntityEnclosingRequestBase) {
            String text = JacksonUtil.useDefaultMapper().toJson(body);
            if (StringUtils.isNotBlank(text)) {
                StringEntity stringEntity = new StringEntity(text, Charset.forName("UTF-8"));
                ((HttpEntityEnclosingRequestBase) httpRequestBase).setEntity(stringEntity);
            }
        }

        return this;
    }

    public Credentials getCredentials() {
        return credentials;
    }

    public HttpRequestBuilder setCredentials(Credentials credentials) {
        this.credentials = credentials;
        return this;
    }
}
